package com.ruoyi.xxljob.admin.controller;

import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.xxljob.admin.core.complete.XxlJobCompleter;
import com.ruoyi.xxljob.admin.core.exception.XxlJobException;
import com.ruoyi.xxljob.admin.core.model.XxlJobGroup;
import com.ruoyi.xxljob.admin.core.model.XxlJobInfo;
import com.ruoyi.xxljob.admin.core.model.XxlJobLog;
import com.ruoyi.xxljob.admin.core.scheduler.XxlJobScheduler;
import com.ruoyi.xxljob.admin.core.util.I18nUtil;
import com.ruoyi.xxljob.admin.dao.XxlJobGroupDao;
import com.ruoyi.xxljob.admin.dao.XxlJobInfoDao;
import com.ruoyi.xxljob.admin.dao.XxlJobLogDao;
import com.ruoyi.xxljob.core.biz.ExecutorBiz;
import com.ruoyi.xxljob.core.biz.model.KillParam;
import com.ruoyi.xxljob.core.biz.model.LogParam;
import com.ruoyi.xxljob.core.biz.model.LogResult;
import com.ruoyi.xxljob.core.biz.model.ReturnT;
import com.ruoyi.xxljob.core.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 调度日志相关
 *
 * @author wjialong
 */
@RestController
@RequestMapping("/log")
public class JobLogController extends BaseController {
    private static Logger logger = LoggerFactory.getLogger(JobLogController.class);

    @Resource
    private XxlJobGroupDao xxlJobGroupDao;
    @Resource
    public XxlJobInfoDao xxlJobInfoDao;
    @Resource
    public XxlJobLogDao xxlJobLogDao;

    @RequestMapping
    public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") Integer jobId) {

        // 执行器列表
        List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();

        // filter group
        List<XxlJobGroup> jobGroupList = JobInfoController.filterJobGroupByRole(request, jobGroupList_all);
        if (jobGroupList == null || jobGroupList.size() == 0) {
            throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
        }

        model.addAttribute("JobGroupList", jobGroupList);

        // 任务
        if (jobId > 0) {
            XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
            if (jobInfo == null) {
                throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid"));
            }

            model.addAttribute("jobInfo", jobInfo);

            // valid permission
            JobInfoController.validPermission(request, jobInfo.getJobGroup());
        }

        return "joblog/joblog.index";
    }

    @GetMapping("/getJobsByGroup")
    public AjaxResult getJobsByGroup(int jobGroup) {
        List<XxlJobInfo> list = xxlJobInfoDao.getJobsByGroup(jobGroup);
        return AjaxResult.success(list);
    }

    /**
     * 获取调度日志的分页列表
     *
     * @param xxlJobLog
     * @param logStatus
     * @return
     */
    @RequiresPermissions("xxl-job:log:query")
    @GetMapping("/list")
    public TableDataInfo list(XxlJobLog xxlJobLog, int logStatus) {
        startPage();
        // parse param
        Map<String, Object> params = xxlJobLog.getParams();
        String beginTime = (String) params.get("beginTime");
        String endTime = (String) params.get("endTime");
        Date triggerTimeStart = null;
        Date triggerTimeEnd = null;
        if (beginTime != null && endTime != null) {
            triggerTimeStart = DateUtil.parseDateTime(beginTime);
            triggerTimeEnd = DateUtil.parseDateTime(endTime);
        }
        List<XxlJobLog> list = xxlJobLogDao.pageList(0, 0, xxlJobLog.getJobGroup(), xxlJobLog.getJobId(),
                triggerTimeStart, triggerTimeEnd, logStatus);
        return getDataTable(list);
    }

    @GetMapping("/logDetailPage")
    public String logDetailPage(int id, Model model) {

        // base check
        ReturnT<String> logStatue = ReturnT.SUCCESS;
        XxlJobLog jobLog = xxlJobLogDao.load(id);
        if (jobLog == null) {
            throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
        }

        model.addAttribute("triggerCode", jobLog.getTriggerCode());
        model.addAttribute("handleCode", jobLog.getHandleCode());
        model.addAttribute("logId", jobLog.getId());
        return "joblog/joblog.detail";
    }

    /**
     * 获取执行日志数据
     *
     * @param logId
     * @param fromLineNum
     * @return
     */
    @RequiresPermissions("xxl-job:log:query")
    @PostMapping("/logDetailCat")
    public AjaxResult logDetailCat(long logId, int fromLineNum) {
        try {
            // valid
            XxlJobLog jobLog = xxlJobLogDao.load(logId);    // todo, need to improve performance
            if (jobLog == null) {
                return AjaxResult.error(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid"));
            }

            // log cat
            ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
            ReturnT<LogResult> logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), logId, fromLineNum));

            // is end
            if (logResult.getContent() != null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
                if (jobLog.getHandleCode() > 0) {
                    logResult.getContent().setEnd(true);
                }
            }

            return AjaxResult.success(logResult.getMsg(), logResult.getContent());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return AjaxResult.error(ReturnT.FAIL_CODE, e.getMessage());
        }
    }


    /**
     * 终止任务
     *
     * @param id
     * @return
     */
    @PostMapping("/logKill")
    public AjaxResult logKill(int id) {
        // base check
        XxlJobLog log = xxlJobLogDao.load(id);
        XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
        if (jobInfo == null) {
            return AjaxResult.error(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
        }
        if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
            return AjaxResult.error(500, I18nUtil.getString("joblog_kill_log_limit"));
        }

        // request of kill
        ReturnT<String> runResult = null;
        try {
            ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress());
            runResult = executorBiz.kill(new KillParam(jobInfo.getId()));
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            runResult = new ReturnT<String>(500, e.getMessage());
        }

        if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
            log.setHandleCode(ReturnT.FAIL_CODE);
            log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":" + (runResult.getMsg() != null ? runResult.getMsg() : ""));
            log.setHandleTime(new Date());
            XxlJobCompleter.updateHandleInfoAndFinish(log);
            return AjaxResult.success(runResult.getMsg());
        } else {
            return AjaxResult.error(500, runResult.getMsg());
        }
    }

    @PostMapping("/clearLog")
    public AjaxResult clearLog(int jobGroup, int jobId, int type) {
        Date clearBeforeTime = null;
        int clearBeforeNum = 0;
        if (type == 1) {
            clearBeforeTime = DateUtil.addMonths(new Date(), -1);    // 清理一个月之前日志数据
        } else if (type == 2) {
            clearBeforeTime = DateUtil.addMonths(new Date(), -3);    // 清理三个月之前日志数据
        } else if (type == 3) {
            clearBeforeTime = DateUtil.addMonths(new Date(), -6);    // 清理六个月之前日志数据
        } else if (type == 4) {
            clearBeforeTime = DateUtil.addYears(new Date(), -1);    // 清理一年之前日志数据
        } else if (type == 5) {
            clearBeforeNum = 1000;        // 清理一千条以前日志数据
        } else if (type == 6) {
            clearBeforeNum = 10000;        // 清理一万条以前日志数据
        } else if (type == 7) {
            clearBeforeNum = 30000;        // 清理三万条以前日志数据
        } else if (type == 8) {
            clearBeforeNum = 100000;    // 清理十万条以前日志数据
        } else if (type == 9) {
            clearBeforeNum = 0;            // 清理所有日志数据
        } else {
            return AjaxResult.error(I18nUtil.getString("joblog_clean_type_unvalid"));
        }

        List<Long> logIds = null;
        do {
            logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
            if (logIds != null && logIds.size() > 0) {
                xxlJobLogDao.clearLog(logIds);
            }
        } while (logIds != null && logIds.size() > 0);

        return AjaxResult.success();
    }

//    @GetMapping("/pageList")
//    public Map<String, Object> pageList(HttpServletRequest request,
//                                        @RequestParam(required = false, defaultValue = "0") int start,
//                                        @RequestParam(required = false, defaultValue = "10") int length,
//                                        int jobGroup, int jobId, int logStatus, String filterTime) {
//
//        // valid permission
//        JobInfoController.validPermission(request, jobGroup);    // 仅管理员支持查询全部；普通用户仅支持查询有权限的 jobGroup
//
//        // parse param
//        Date triggerTimeStart = null;
//        Date triggerTimeEnd = null;
//        if (filterTime != null && filterTime.trim().length() > 0) {
//            String[] temp = filterTime.split(" - ");
//            if (temp.length == 2) {
//                triggerTimeStart = DateUtil.parseDateTime(temp[0]);
//                triggerTimeEnd = DateUtil.parseDateTime(temp[1]);
//            }
//        }
//
//        // page query
//        List<XxlJobLog> list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
//        int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
//
//        // package result
//        Map<String, Object> maps = new HashMap<String, Object>();
//        maps.put("recordsTotal", list_count);       // 总记录数
//        maps.put("recordsFiltered", list_count);    // 过滤后的总记录数
//        maps.put("data", list);                     // 分页列表
//        return maps;
//    }

}
